package learning.spring.binarytea;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.web.servlet.mvc.UrlFilenameViewController;

import javax.sql.DataSource;
import java.util.Objects;

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    private final ObjectProvider<DataSource> dataSources;

    public WebSecurityConfiguration(ObjectProvider<DataSource> dataSources) {
        this.dataSources = dataSources;
    }

    @Bean("/login")
    public UrlFilenameViewController loginController() {
        UrlFilenameViewController controller = new UrlFilenameViewController();
        controller.setSupportedMethods(HttpMethod.GET.name());
        controller.setSuffix(".html");
        return controller;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .mvcMatchers("/actuator/*").permitAll()
                .anyRequest().authenticated().and()
                .formLogin()
                .loginPage("/login").permitAll()
                .defaultSuccessUrl("/order")
                .failureUrl("/login")
                .loginProcessingUrl("/doLogin")
                .usernameParameter("user")
                .passwordParameter("pwd").and()
                .httpBasic().and()
                // 以下是rememberMe的配置
                .rememberMe()
                .key("binarytea")// 私钥
                .rememberMeParameter("remember")
                .tokenValiditySeconds(24 * 60 * 60)// 令牌的有效期
                .tokenRepository(this.persistentTokenRepository(dataSources))// 配置持久化令牌
                .userDetailsService(this.userDetailsService(dataSources)).and()
                // 下面是logout的配置
                .logout()
                .logoutSuccessUrl("/")
                .logoutRequestMatcher(new OrRequestMatcher(
                        new AntPathRequestMatcher("/logout", "GET"),
                        new AntPathRequestMatcher("/logout", "POST")));
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(ObjectProvider<DataSource> dataSources) {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(Objects.requireNonNull(dataSources.getIfAvailable()));
        tokenRepository.setCreateTableOnStartup(false);// 不自动创建表 TODO 实际运行时还是自动创建了
        return tokenRepository;
    }

    @Bean
    public UserDetailsService userDetailsService(ObjectProvider<DataSource> dataSources) {
        JdbcUserDetailsManager userDetailsManager = new JdbcUserDetailsManager();
        userDetailsManager.setDataSource(Objects.requireNonNull(dataSources.getIfAvailable()));
        UserDetails manager = User.builder()
                .username("HanMeimei")
                // .password("{bcrypt}$2a$10$iAty2GrJu9WfpksIen6qX.vczLmXlp.1q1OHBxWEX8BIldtwxHl3u")
                .password("{bcrypt}$2a$10$2Bk.lnrnd4H2zGW/GMPg8OeF/XaVX0fZXIevtVZG9CuUy2xkgHVyS")// 明文密码：showmethemoney
                .authorities("READ_ORDER", "WRITE_ORDER")
                .build();
        userDetailsManager.createUser(manager);
        return userDetailsManager;
    }

}
